/*******************************************************************************
 * Includes
 ******************************************************************************/
#include "hpm6e00.h"
#include "Wed_framework.h"

/*******************************************************************************
 * Extern
 ******************************************************************************/
extern int __dma_zone_start__;
extern int __dma_zone_length__;

extern struct Wed_mii_opts    __g_mii_opts;
extern struct Wed_mii_opts    __g_mii_gpio_opts;
extern struct Wed_netdev_opts __g_netdev_opts;

/*******************************************************************************
 * Macro operate
 ******************************************************************************/
#define DMA_ZONE_START    (((uint32_t)&__dma_zone_start__))
#define DMA_ZONE_LENGTH   (((uint32_t)&__dma_zone_length__))

/*******************************************************************************
 * Code
 ******************************************************************************/
/**
 * \brief 平台时钟初始化
 */
static void __plat_board_clk_init(void){
    hpm_pmp_entry_t pmp_entry[1];

    uint32_t cpu0_freq = clk_freq_get(CLK_SRC_GROUP_COMMON, clock_node_cpu0);
    if (cpu0_freq == PLLCTL_SOC_PLL_REFCLK_FREQ) {
        //todo
    }

    clk_group_add(sysctl_resource_cpu0, 0);
    clk_group_add(sysctl_resource_mchtmr0, 0);
    clk_group_add(sysctl_resource_ahbp, 0);
    clk_group_add(sysctl_resource_axis, 0);
    clk_group_add(sysctl_resource_axic, 0);
    clk_group_add(sysctl_resource_axin, 0);
    clk_group_add(sysctl_resource_rom0, 0);
    clk_group_add(sysctl_resource_xpi0, 0);
    clk_group_add(sysctl_resource_lmm0, 0);
    clk_group_add(sysctl_resource_lmm1, 0);
    clk_group_add(sysctl_resource_ram0, 0);
    clk_group_add(sysctl_resource_ram1, 0);
    clk_group_add(sysctl_resource_hdma, 0);
    clk_group_add(sysctl_resource_xdma, 0);
    clk_group_add(sysctl_resource_gpio, 0);
    clk_group_add(sysctl_resource_ptpc, 0);
    clk_group_add(sysctl_resource_usb0, 0);
    clk_group_add(sysctl_resource_uart0, 0);
    clk_group_add(sysctl_resource_tsn0, 0);
    clk_group_add(sysctl_resource_eth0, 0);
    clk_group_add(sysctl_resource_esc0, 0);
    clk_group_add(sysctl_resource_ref0, 0);
    clk_group_add(sysctl_resource_ref1, 0);

    /* 连接组 0 到 CPU0 */
    clk_group_cpu_connect(0, 0);

    clk_group_add(sysctl_resource_cpu1, 0);
    clk_group_add(sysctl_resource_mchtmr1, 0);
    /* 连接组 1 到 CPU1 */
    clk_group_cpu_connect(1, 1);

    /* 设置 DCDC 电压 1275mv */
    pcfg_dcdc_voltage_set(1275);

    /* 设置时钟分频 */
    clk_source_divider_set(clock_node_cpu0, CLK_SRC_GROUP_COMMON, clock_source_pll0_clk0, 1);
    clk_source_divider_set(clock_node_cpu1, CLK_SRC_GROUP_COMMON, clock_source_pll0_clk0, 1);

    clk_source_divider_set(clock_node_mchtmr0, CLK_SRC_GROUP_COMMON, clock_source_osc0_clk0, 1);
    clk_source_divider_set(clock_node_mchtmr1, CLK_SRC_GROUP_COMMON, clock_source_osc0_clk0, 1);

    clk_source_divider_set(clock_node_uart0, CLK_SRC_GROUP_COMMON, clock_source_osc0_clk0, 0);
    /* 配置 AXIN 为 100M 时钟 */
   // clk_source_divider_set(clock_node_axin, CLK_SRC_GROUP_COMMON, clock_source_pll1_clk0, 8);
    /* TSN1 RMII 模式设置端口时钟为 50MHZ */
    clk_source_divider_set(clock_node_tsn1, CLK_SRC_GROUP_COMMON, clock_source_pll1_clk2, 5);
    /* TSN1 RMII 模式设置端口时钟为 50MHZ */
    clk_source_divider_set(clock_node_tsn3, CLK_SRC_GROUP_COMMON, clock_source_pll1_clk2, 5);

    /* 使能 ESC 时钟 */
    esc_core_clk_enable(1);
    /* 使能 ESC PHY 时钟 */
    esc_phy_clk_enable(1);

    /* 初始化 DMA 内存 */

    /* 检查长度是否 2 的倍数对齐*/
    if ((DMA_ZONE_LENGTH == 0) || (DMA_ZONE_LENGTH & (DMA_ZONE_LENGTH - 1U)) || (DMA_ZONE_START & (DMA_ZONE_LENGTH - 1U))) {
        while(1);
    }

    pmp_entry[0].pmp_addr    = PMP_NAPOT_ADDR(DMA_ZONE_START, DMA_ZONE_LENGTH);
    pmp_entry[0].pmp_cfg.val = PMP_CFG(PMP_READ_EN, PMP_WRITE_EN, PMP_EXECUTE_EN, PMP_ADDR_MATCH_NAPOT, PMP_REG_UNLOCK);
    pmp_entry[0].pma_addr    = PMA_NAPOT_ADDR(DMA_ZONE_START, DMA_ZONE_LENGTH);
    pmp_entry[0].pma_cfg.val = PMA_CFG(PMP_ADDR_MATCH_NAPOT, PMA_MEM_TYPE_MEM_NON_CACHE_BUF, PMA_AMO_EN);

    hpm_pmp_cfg(&pmp_entry[0], NELEMENTS(pmp_entry));
}

/**
 * \brief 引脚初始化
 */
static void __plat_board_pins_init(void){
    /* 初始化串口 0 引脚 */
    ioc_pad_func_set(IOC_PAD_PA00, IOC_PA00_FUNC_CTL_UART0_TXD);
    ioc_pad_func_set(IOC_PAD_PA01, IOC_PA01_FUNC_CTL_UART0_RXD);

    /* 初始化 TSW 端口 1 引脚 */
    ioc_pad_func_set(IOC_PAD_PA16, IOC_PA16_FUNC_CTL_TSW0_P1_RXDV);
    ioc_pad_ctrl_set(IOC_PAD_PA16, IOC_PAD_PAD_CTL_DS_SET(6));
    ioc_pad_func_set(IOC_PAD_PA17, IOC_PA17_FUNC_CTL_TSW0_P1_RXD_0);
    ioc_pad_ctrl_set(IOC_PAD_PA17, IOC_PAD_PAD_CTL_DS_SET(6));
    ioc_pad_func_set(IOC_PAD_PA18, IOC_PA18_FUNC_CTL_TSW0_P1_RXD_1);
    ioc_pad_ctrl_set(IOC_PAD_PA18, IOC_PAD_PAD_CTL_DS_SET(6));
    ioc_pad_func_set(IOC_PAD_PA24, IOC_PA24_FUNC_CTL_TSW0_P1_TXCK | IOC_PAD_FUNC_CTL_LOOP_BACK_SET(1));
    ioc_pad_ctrl_set(IOC_PAD_PA24, IOC_PAD_PAD_CTL_DS_SET(6));
    ioc_pad_func_set(IOC_PAD_PA25, IOC_PA25_FUNC_CTL_TSW0_P1_TXD_0);
    ioc_pad_ctrl_set(IOC_PAD_PA25, IOC_PAD_PAD_CTL_DS_SET(6));
    ioc_pad_func_set(IOC_PAD_PA26, IOC_PA26_FUNC_CTL_TSW0_P1_TXD_1);
    ioc_pad_func_set(IOC_PAD_PA29, IOC_PA29_FUNC_CTL_TSW0_P1_TXEN);
    ioc_pad_ctrl_set(IOC_PAD_PA29, IOC_PAD_PAD_CTL_DS_SET(6));

    /* 初始化 TSW 端口 3 引脚 */
    ioc_pad_func_set(IOC_PAD_PF02, IOC_PF02_FUNC_CTL_TSW0_P3_TXCK | IOC_PAD_FUNC_CTL_LOOP_BACK_SET(1));
    ioc_pad_ctrl_set(IOC_PAD_PF02, IOC_PAD_PAD_CTL_DS_SET(6));
    ioc_pad_func_set(IOC_PAD_PF03, IOC_PF03_FUNC_CTL_TSW0_P3_TXD_0);
    ioc_pad_ctrl_set(IOC_PAD_PF03, IOC_PAD_PAD_CTL_DS_SET(6));
    ioc_pad_func_set(IOC_PAD_PF04, IOC_PF04_FUNC_CTL_TSW0_P3_TXD_1);
    ioc_pad_ctrl_set(IOC_PAD_PF04, IOC_PAD_PAD_CTL_DS_SET(6));
    ioc_pad_func_set(IOC_PAD_PF07, IOC_PF07_FUNC_CTL_TSW0_P3_TXEN);
    ioc_pad_ctrl_set(IOC_PAD_PF07, IOC_PAD_PAD_CTL_DS_SET(6));
    ioc_pad_func_set(IOC_PAD_PF08, IOC_PF08_FUNC_CTL_TSW0_P3_RXDV);
    ioc_pad_ctrl_set(IOC_PAD_PF08, IOC_PAD_PAD_CTL_DS_SET(6));
    ioc_pad_func_set(IOC_PAD_PF09, IOC_PF09_FUNC_CTL_TSW0_P3_RXD_0);
    ioc_pad_ctrl_set(IOC_PAD_PF09, IOC_PAD_PAD_CTL_DS_SET(6));
    ioc_pad_func_set(IOC_PAD_PF10, IOC_PF10_FUNC_CTL_TSW0_P3_RXD_1);
    ioc_pad_ctrl_set(IOC_PAD_PF10, IOC_PAD_PAD_CTL_DS_SET(6));

    /* 初始化 MDC 与 MDIO 引脚 */
    ioc_pad_func_set(IOC_PAD_PE00, IOC_PE00_FUNC_CTL_TSW0_P1_MDC);
    ioc_pad_func_set(IOC_PAD_PE01, IOC_PE01_FUNC_CTL_TSW0_P1_MDIO);
    ioc_pad_func_set(IOC_PAD_PF00, IOC_PF00_FUNC_CTL_GPIO_F_00);
    ioc_pad_func_set(IOC_PAD_PF01, IOC_PF01_FUNC_CTL_GPIO_F_01);
    ioc_pad_ctrl_set(IOC_PAD_PF00, IOC_PAD_PAD_CTL_PS_SET(1) | IOC_PAD_PAD_CTL_PE_SET(1));
    ioc_pad_ctrl_set(IOC_PAD_PF01, IOC_PAD_PAD_CTL_PS_SET(1) | IOC_PAD_PAD_CTL_PE_SET(1));
    ioc_pad_gpio_output_set(IOC_PAD_PF00);
    ioc_pad_gpio_output_set(IOC_PAD_PF01);
}

/**
 * \brief UART 初始化
 */
static int __uart_init(void *p_opts_arg){
    struct hpm_uart_cfg  cfg;
    hpm_uart_reg_t      *p_uart_reg = (hpm_uart_reg_t *)p_opts_arg;

    uart_cfg_default_set(&cfg);

    cfg.fifo_enable    = 1;
    cfg.src_freq_in_hz = clk_freq_get(CLK_SRC_GROUP_COMMON, clock_node_uart0);

    return uart_init(p_uart_reg, &cfg);
}

/**
 * \brief UART 字节发送
 */
static int __uart_byte_send(void *p_opts_arg, uint8_t data){
    return uart_byte_send((hpm_uart_reg_t *)p_opts_arg, data);
}


/* \brief UART 操作函数集 */
static struct Wed_uart_opts __g_uart_opts = {
    .p_fn_init       = __uart_init,
    .p_fn_byte_write = __uart_byte_send,
};

/**
 * \brief GPIO 初始化
 */
static int __gpio_init(void *p_opts_arg, uint32_t port_num, uint32_t pin_num, uint32_t flag){
    ioc_pad_func_set(pin_num, 0);

    if (flag & WED_GPIO_DIR_FLAG_MASK) {

    } else {
        ioc_pad_gpio_output_set(pin_num);

        ioc_pad_gpio_sta_set(pin_num, (flag & WED_GPIO_OUTPUT_STA_FLAG_MASK));
    }
    return 0;
}

/**
 * \brief GPIO 状态设置
 */
static int __gpio_sta_set(void *p_opts_arg, uint32_t port_num, uint32_t pin_num, uint8_t sta){
    return ioc_pad_gpio_sta_set(pin_num, sta);
}

/**
 * \brief GPIO 翻转
 */
static int __gpio_toggle(void *p_opts_arg, uint32_t port_num, uint32_t pin_num){
    return ioc_pad_gpio_sta_toggle(pin_num);
}

/* \brief GPIO 操作函数集 */
static struct Wed_gpio_opts __g_gpio_opts = {
    .p_fn_init       = __gpio_init,
    .p_fn_sta_set    = __gpio_sta_set,
    .p_fn_sta_toggle = __gpio_toggle,
};

/**
 * \brief 平台外设注册
 */
static void __plat_board_device_register(void){
    Wed_uart_register("uart0", &__g_uart_opts, HPM_UART0, 0);
    Wed_print_dev_regsiter("uart0");
    Wed_gpio_register("led_run", &__g_gpio_opts, NULL, 0, IOC_PAD_PF29, WED_GPIO_OUTPUT_LOW_FLAG);
    Wed_gpio_register("phy0_reset", &__g_gpio_opts, NULL, 0, IOC_PAD_PA22, WED_GPIO_OUTPUT_HIGH_FLAG);
    /* 注册 PHY 复位引脚 */
    Wed_gpio_register("phy2_reset", &__g_gpio_opts, NULL, 0, IOC_PAD_PF05, WED_GPIO_OUTPUT_HIGH_FLAG);
    Wed_phy_register("phy0", &__g_mii_opts, (void *)TSW_TSNPORT_PORT1, "phy0_reset");
    Wed_phy_register("phy2", &__g_mii_gpio_opts, (void *)TSW_TSNPORT_PORT3, "phy2_reset");
    Wed_netdev_register("tsn0", &__g_netdev_opts, (void *)TSW_TSNPORT_PORT1);
    Wed_netdev_register("tsn2", &__g_netdev_opts, (void *)TSW_TSNPORT_PORT3);
}

//extern uint8_t *__g_p_recv_buf;
//static uint8_t buddd[512] = {0};
//
//int tsw_recv_data(uint8_t *p_buf_data){
//    int ret;
//
//    struct tsw_frame frame = {0};
//
//    ret = tsw_frame_recv(&frame);
//    if (ret == 0) {
//        memcpy(p_buf_data, __g_p_recv_buf, frame.len);
//        return frame.len;
//    }
//    return ret;
//}

/**
 * \brief 平台板卡初始化
 *
 * @return 成功返回 0
 */
int Wed_plat_board_init(void){
    /* 时钟初始化 */
    __plat_board_clk_init();
    /* 引脚初始化 */
    __plat_board_pins_init();
    /* 平台外设注册 */
    __plat_board_device_register();
    /* 初始化 DMA 内存 */
    Wed_mem_dma_init((void *)DMA_ZONE_START, DMA_ZONE_LENGTH);

    return 0;

}
